
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 生产者消费者模型：
 * 1：判断
 * 2：干活
 * 3：通知
 * 这三部完成就可以了
 * 注意：多线程判断用while，为了防止虚假唤醒
 * sync与lock区别：
 *  前者为jdk关键字，底层为moniter对象（这里会exit两次，为了防止异常情况也能退出）；后者为一个类
 *  前者不能精确唤醒；后者可以
 *  前者不能手动释放锁，后者需要手动释放
 *  前者不能被打断，后者可以被interrupt()打断
 *  前者为非公平锁，后者可以通过构造方式true/false进行设置
 *
 */

public class ProductAndConsumerDemo {

    private static volatile int i = 0;

    Lock look = new ReentrantLock();
    Condition condition = look.newCondition();

    public void product() {
        try {
            look.lock();
            while ( i != 0) {
                // 等待
                condition.await();
            }
            System.out.println(Thread.currentThread().getName() + " 生产");
            condition.signal();
            i = 1;
            System.out.println("结束生产");
        } catch (Exception e) {
        } finally {
            look.unlock();
        }
    }


    public void comsumer(){
        try {
            look.lock();
            while (i == 0) {
                condition.await();
            }
            System.out.println(Thread.currentThread().getName() + " 消费");
            // 唤醒
            condition.signal();
            i = 0;
            System.out.println("结束消费");
        } catch (Exception e) {
        } finally {
            look.unlock();
        }

    }
    public static void main(String[] args) {
        ProductAndConsumerDemo productAndConsumerDemo = new ProductAndConsumerDemo();
        new Thread(new product(productAndConsumerDemo)).start();
        new Thread(new consumer(productAndConsumerDemo)).start();

    }


}

class product implements Runnable {

    private ProductAndConsumerDemo productAndConsumerDemo;

    public product(ProductAndConsumerDemo productAndConsumerDemo) {
        this.productAndConsumerDemo = productAndConsumerDemo;
    }

    @Override
    public void run() {
        Thread.currentThread().setName("生产者");
        productAndConsumerDemo.product();

    }
}

class consumer implements Runnable {
    private ProductAndConsumerDemo productAndConsumerDemo;

    public consumer(ProductAndConsumerDemo productAndConsumerDemo) {
        this.productAndConsumerDemo = productAndConsumerDemo;
    }

    @Override
    public void run() {
        Thread.currentThread().setName("消费者");
        productAndConsumerDemo.comsumer();

    }
}


